package ss.pku.jsa.type.io;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

public class MethodQSig extends QSig {
	public List<String> qParams;
	public String qReturn;
	public String qThis;
	public String sig;

	public MethodQSig(List<String> qParams, String qReturn, String qThis,
			String jniSig) {
		this.qParams = qParams;
		this.qReturn = qReturn;
		this.qThis = qThis;
		this.sig = jniSig;
	}

	public String toString() {
		StringBuilder ret = new StringBuilder();
		ret.append("method:");
		ret.append('\n');

		ret.append(this.sig);
		ret.append('\n');

		ret.append("this:" + this.qThis);
		ret.append('\n');

		ret.append("ret:" + this.qReturn);
		ret.append('\n');

		for (String p : this.qParams) {
			ret.append("param:" + p);
			ret.append('\n');
		}
		ret.append('\n');
		return ret.toString();
	}

	public int hashCode() {
		int result = 1;
		result = 31 * result + (this.sig == null ? 0 : this.sig.hashCode());
		result = 31 * result
				+ (this.qParams == null ? 0 : this.qParams.hashCode());
		result = 31 * result
				+ (this.qReturn == null ? 0 : this.qReturn.hashCode());
		result = 31 * result + (this.qThis == null ? 0 : this.qThis.hashCode());
		return result;
	}

	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		MethodQSig other = (MethodQSig) obj;
		if (this.sig == null) {
			if (other.sig != null)
				return false;
		} else if (!this.sig.equals(other.sig))
			return false;
		if (this.qParams == null) {
			if (other.qParams != null)
				return false;
		} else if (!this.qParams.equals(other.qParams))
			return false;
		if (this.qReturn == null) {
			if (other.qReturn != null)
				return false;
		} else if (!this.qReturn.equals(other.qReturn))
			return false;
		if (this.qThis == null) {
			if (other.qThis != null)
				return false;
		} else if (!this.qThis.equals(other.qThis))
			return false;
		return true;
	}

	public boolean[] tracked() {
		int len = this.qParams.size() + 2;
		boolean[] ret = new boolean[len];
		ret[0] = isTracked(this.qThis);
		ret[1] = isTracked(this.qReturn);
		for (int i = 0; i < this.qParams.size(); i++)
			ret[(i + 2)] = isTracked((String) this.qParams.get(i));
		return ret;
	}

	@SuppressWarnings("rawtypes")
	public boolean asGoodAs(MethodQSig other) {
		if (this.sig == null) {
			if (other.sig != null)
				throw new IllegalArgumentException("Comparing " + this.sig
						+ " with null jniSig");
		} else if (!this.sig.equals(other.sig))
			throw new IllegalArgumentException("Comparing " + this.sig
					+ " with " + other.sig);
		if (this.qParams == null) {
			if (other.qParams != null)
				throw new IllegalArgumentException("Comparing " + this.sig
						+ " with " + other.sig
						+ " this has params, other doesn't");
		} else {
			Iterator otherPs = other.qParams.iterator();
			for (String p : this.qParams) {
				String otherP = (String) otherPs.next();
				if ((p.contains("mutable")) && (!otherP.contains("mutable"))) {
					return false;
				}
			}
		}
		if (this.qReturn == null) {
			if (other.qReturn != null)
				throw new IllegalArgumentException("Comparing " + this.sig
						+ " with " + other.sig
						+ " this has return, other doesn't");
		} else if ((this.qReturn.contains("mutable"))
				&& (!other.qReturn.contains("mutable"))) {
			return false;
		}
		if (this.qThis == null) {
			if (other.qThis != null)
				throw new IllegalArgumentException("Comparing " + this.sig
						+ " with " + other.sig
						+ " this has this, other doesn't");
		} else if ((this.qThis.contains("mutable"))
				&& (!other.qThis.contains("mutable")))
			return false;
		return true;
	}

	public static MethodQSig read(BufferedReader in) throws IOException {
		String jniSig = in.readLine();
		if (jniSig == null) {
			throw new IllegalArgumentException("no jniSig");
		}
		String qThis = in.readLine();
		if ((qThis == null)
				|| (!qThis.substring(0, "this:".length()).equals("this:"))) {
			throw new IllegalArgumentException("qThis line reads: " + qThis);
		}
		qThis = qThis.substring("this:".length());

		String qReturn = in.readLine();
		if ((qReturn == null)
				|| (!qReturn.substring(0, "ret:".length()).equals("ret:"))) {
			throw new IllegalArgumentException("qReturn line reads: " + qReturn);
		}
		qReturn = qReturn.substring("ret:".length());

		List<String> qParams = new Vector<String>();
		String qParam;
		while (!(qParam = in.readLine().trim()).equals("")) {
			if (qParam.substring(0, "param:".length() - 1).equals("param:")) {
				throw new IllegalArgumentException("qParam line reads: "
						+ qParam);
			}
			qParam = qParam.substring("param:".length());
			qParams.add(qParam);
		}
		return new MethodQSig(qParams, qReturn, qThis, jniSig);
	}
}
